/*
 * server_mgr.cpp
 *
 *  Created on: Dec 26, 2013
 *      Author: killerg
 */

#include "bill_deps.h"
#include "bill.h"
#include "bill_cfg.h"
#include "server_mgr.h"
#include "bill_console.h"
#include "share/db_mgr.h"
#include "share/clock.h"

player_info_t* server_mgr_t::get_player_info(int serverid, const string &account) {
    auto serverinfo = serverinfos.get(serverid);
    if (NULL == serverinfo)
        return NULL;

    return serverinfo->players.get(account);
}
void server_mgr_t::refresh_player_info(int serverid, const string &account, const player_info_t &info) {
    auto serverinfo = serverinfos.get(serverid);
    if (NULL == serverinfo) {
        serverinfo = new server_info_t;
        serverinfo->sess = NULL;
        serverinfos.set(serverid, serverinfo);
    }

    auto playerinfo = serverinfo->players.get(account);
    if (NULL == playerinfo) {
        playerinfo = new player_info_t;
        serverinfo->players.set(account, playerinfo);
    	if (g_cfg->trace)
    		UTIL_LOG(E, "player info create\n serverid:%d account:%s\n", serverid, account.c_str());
    }

    *playerinfo = info;
}

void server_mgr_t::post_order(int serverid, const string &orderId, int playerid, int payFee, const string &machinecode, function<void(bool)> cb) {
	if (dealt_order.count(orderId) > 0) {
		cb(true);
		return;
	}

    Json::Value value;
    value["objtype"] = "order";
    value["serverid"] = serverid;
    value["orderid"] = orderId;
    value["playerid"] = playerid;
    value["payfee"] = payFee;
    value["dealt"] = false;
    value["mc"] = machinecode;

    dealt_order.insert(orderId);
    bool ret = g_db->set(
            fmt_cstr("order:%d:%s", serverid, orderId.c_str()),
            value,
            [machinecode, playerid, payFee, orderId, serverid, cb, this](db_error_t err){
    			--db_set;
                if (DBE_Success != err) {
                    dealt_order.erase(orderId);
                    cb(false);
                    return;
                }

                auto svrinfo = serverinfos.get(serverid);
                if (NULL == svrinfo) {
                	dealt_order.erase(orderId);
                    cb(false);
                    return;
                }

                auto order = new order_t;
                order->orderId = orderId;
                order->playerid = playerid;
                order->payfee = payFee;
                order->dealt = false;
                order->machinecode = machinecode;
                svrinfo->orders.push_back(order);

                cb(true);
            });
    if (!ret) {
    	dealt_order.erase(orderId);
        cb(false);
        return;
    } else {
        ++db_set;
    }
}

bool server_mgr_t::init() {

	const char* path_accounts =
			"/_design/bill/_view/accounts"
			"?stale=false"
//			"&full_set=true"
			"&connection_timeout=60000";

	bool ret = g_db->view(
			path_accounts,
			[&ret](db_error_t err, const Json::Value &json){
				switch (err) {
				case DBE_Success: {
					if (!json.get("error", Json::nullValue).isNull()) {
						UTIL_LOG(E,
								"err load accounts view %s %s",
								json["error"].asCString(),
								json["reason"].asCString());
						ret = false;
						break;
					}
					const Json::Value &rows = json["rows"];
					for (auto itr = rows.begin(); itr != rows.end(); ++itr) {
						const Json::Value &value = (*itr)["value"];
						if (value.isNull())
							continue;

						player_info_t info;
						info.playerid = value["playerid"].asInt();
						info.playername = value["playername"].asCString();
						info.account = value["account"].asCString();
						g_svrmgr->refresh_player_info(
								value["serverid"].asInt(),
								info.account,
								info);
					}
				}
				break;
				default:
				    UTIL_LOG(E, "bill accounts view load fail");
					ret = false;
					break;
				}
			});

    if (ret)
        g_db->wait();
    if (!ret)
		return false;


	const char* path_bills =
			"/_design/bill/_view/orders"
			"?stale=false"
			"&key=false"
			"&full_set=true"
			"&connection_timeout=60000";

	ret = g_db->view(
			path_bills,
			[&ret](db_error_t err, const Json::Value &json){
				switch (err) {
				case DBE_Success: {
					if (!json.get("error", Json::nullValue).isNull()) {
						UTIL_LOG(E,
								"err load orders view %s %s",
								json["error"].asCString(),
								json["reason"].asCString());
						ret = false;
						break;
					}
					const Json::Value &rows = json["rows"];
					for (auto itr = rows.begin(); itr != rows.end(); ++itr) {
						const Json::Value &value = (*itr)["value"];
						if (value.isNull())
							continue;

				        auto svrinfo = g_svrmgr->serverinfos.get(value["serverid"].asInt());
				        if (svrinfo == NULL) {
				        	svrinfo = new server_info_t;
				        	svrinfo->sess = NULL;
				        	g_svrmgr->serverinfos.set(value["serverid"].asInt(), svrinfo);
				        }

				        auto order = new order_t;
				        order->orderId = value["orderid"].asCString();
				        order->playerid = value["playerid"].asInt();
				        order->payfee = value["payfee"].asDouble();
				        order->dealt = value["dealt"].asBool();

				        svrinfo->orders.push_back(order);
					}
				}
				break;
				default:
                    UTIL_LOG(E, "bill orders view load fail");
					ret = false;
					break;
				}
			});
	if (ret)
	    g_db->wait();

    g_console->watch_n("server_num", [this]()->int32_t{ return serverinfos.size(); });
    g_console->watch_n("dealtorder_num", [this]()->int32_t{ return dealt_order.size(); });
    g_console->watch_n("order_post_delta", [this]()->int32_t{ return order_post_delta; });
    g_console->watch_n("order_post", [this]()->int32_t{ return order_post; });
    g_console->watch_n("db_set", [this]()->int32_t{
    	return db_set;
    });

    g_console->watch_n("player_info_num", [this]()->int32_t{
    	int32_t total = 0;
    	for (auto &itr : serverinfos) {
    		total += itr.second->players.size();
    	}
    	return total;
    });

    g_console->watch_n("order_num", [this]()->int32_t{
    	int32_t total = 0;
    	for (auto &itr : serverinfos) {
    		total += itr.second->orders.size();
    	}
    	return total;
    });

    return ret;
}

void server_mgr_t::destroy() {
	for (auto svrinfo:serverinfos) {
		for (auto order:svrinfo.second->orders) {
			safe_del(order);
		}
		svrinfo.second->orders.clear();

		for (auto plrinfo:svrinfo.second->players) {
			safe_del(plrinfo.second);
		}
		svrinfo.second->players.clear();
	}
	serverinfos.clear();
}

void server_mgr_t::update() {
	if (g_clock->sec_jump) {
		order_post_delta = order_post - order_post_prev;
		order_post_prev = order_post;
	}
}
